import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

import org.rsbot.event.listeners.PaintListener;
import org.rsbot.script.Constants;
import org.rsbot.script.Script;
import org.rsbot.script.ScriptManifest;
import org.rsbot.script.wrappers.RSArea;
import org.rsbot.script.wrappers.RSInterface;
import org.rsbot.script.wrappers.RSNPC;
import org.rsbot.script.wrappers.RSObject;
import org.rsbot.script.wrappers.RSTile;

@ScriptManifest(authors = { "Henry" }, category = "Mining", name = "Henry's Essence Miner", version = 1.00, description = "<html><style type='text/css'>"
		+ "body {background:url('http://runedev-infinity.org/client/images/back_2.png') repeat}"
		+ "</style><html><head><center><img src=\"http://runedev-infinity.org/client/images/logo.png\">"
		+ "<h1><center><font color=#FFFFFF>"
		+ "Henry's Essence Miner by; Henry"
		+ "</center></font color></h1>"
		+ "</head><br><body>"
		+ "<center><table border=0 cellpadding=1 cellspacing=1 style=border-collapse:collapse width=80% id=AutoNumber1 bgcolor=CCCCCC>"
		+ "<td width=90% align=justify>"
		+ "<font size=2><center><font color=#0000FF>How to set up and start this script.</font></font size></center>"
		+ "<font size=3>Start this script at the east bank in Varrock Have your mining pick on "
		+ "you or in your inventory...<br>"
		+ "Rest: <input type='checkbox' name='rest' id='rest' value='true' /> Yes <br />"
		+ "<center><font color=#0000FF>Good luck and bot safe</font></center></font size>"
		+ "</td></tr></table><br />")
public class henrysEssMiner extends Script implements PaintListener {

	public int doorID = 24381;
	public RSTile doorTile = new RSTile(3253, 3398);
	public int ess = 2491;
	public int[] portal = { 39831 };
	public int teleport = 5913;
	public RSTile[] PathName = { new RSTile(3253, 3420),
			new RSTile(3260, 3427), new RSTile(3260, 3420),
			new RSTile(3260, 3411), new RSTile(3258, 3403),
			new RSTile(3253, 3401) };
	public RSArea area = new RSArea(new RSTile(3252, 3399), new RSTile(3255,
			3404));
	public RSArea bankArea = new RSArea(new RSTile(3250, 3419), new RSTile(
			3257, 3423));
	public int failSafe = 0;
	public int[] mining = { 0, 0 };
	public int lastXP = 0;
	public int count = 0;
	public long startTime = System.currentTimeMillis();
	public int currentOrePrice = 0;
	public int currentOrePrice2 = 0;
	public int[] OreInvID = { 1436, 7936 };
	public int currentOreInventoryID = 1436;
	public int currentOreInventoryID2 = 7936;
	public boolean rest = true;
	public String status = "Starting UP";
	private boolean justIn = true;
	private final Color color1 = new Color(0, 0, 0, 138);
	private final Color color2 = new Color(153, 153, 153, 137);
	private final Color color3 = new Color(255, 0, 0);

	private final BasicStroke stroke1 = new BasicStroke(1);

	private final Font font1 = new Font("Arial", 3, 14);
	private final Font font2 = new Font("Arial", 3, 12);
	private final int[] pickaxes = { 1275, 1265, 1273, 1267, 1271, 13661 };

	private final Image img1 = getImage("http://www.runedev-infinity.org/client/images/Mining_cape_99.png");

	private boolean setAltitude = false;

	private Image getImage(final String url) {
		try {
			return ImageIO.read(new URL(url));
		} catch (final IOException e) {
			return null;
		}
	}

	@Override
    public boolean onStart(final java.util.Map<java.lang.String, java.lang.String> map) {
		mining[0] = skills.getCurrentSkillExp(Constants.STAT_MINING);
		mining[1] = skills.getCurrSkillLevel(Constants.STAT_MINING);
		lastXP = mining[0];
		currentOrePrice = grandExchange.loadItemInfo(currentOreInventoryID)
				.getGuidePrice();
		currentOrePrice2 = grandExchange.loadItemInfo(currentOreInventoryID2)
				.getGuidePrice();
		status = "Done";
		count = 0;
		if(map.get("rest").equals("true")) {
			rest = true;
		} else {
            rest = false;
        }
		startTime = System.currentTimeMillis();
		return true;
	}

	@Override
	public void onRepaint(final Graphics g1) {
		if (lastXP < skills.getCurrentSkillExp(Constants.STAT_MINING)) {
			count++;
			lastXP = skills.getCurrentSkillExp(Constants.STAT_MINING);
			if (getInventoryCount(currentOreInventoryID2) > 0
					&& currentOreInventoryID != currentOreInventoryID2) {
				currentOreInventoryID = currentOreInventoryID2;
				currentOrePrice = currentOrePrice2;
			}
		}
		final Graphics2D g = (Graphics2D) g1;
		long millis = System.currentTimeMillis() - startTime;
		final long hours = millis / (1000 * 60 * 60);
		millis -= hours * (1000 * 60 * 60);
		final long minutes = millis / (1000 * 60);
		millis -= minutes * (1000 * 60);
		final long seconds = millis / 1000;
		final int xpHour = (int) Math.round((skills
				.getCurrentSkillExp(Constants.STAT_MINING) - mining[0])
				* 3600000D / (System.currentTimeMillis() - startTime));
		final int oreHour = (int) Math.round(count * 3600000D
				/ (System.currentTimeMillis() - startTime));
		final int gpHour = (int) Math.round((count * currentOrePrice) * 3600000D
				/ (System.currentTimeMillis() - startTime));
		final int TTL = (int) (((double) skills
				.getXPToNextLevel(Constants.STAT_MINING) / (double) xpHour) * 3600000);
		final String daysToLevel = getFormattedTime(TTL)[0];
		final String hoursToLevel = getFormattedTime(TTL)[1];
		final String minutesToLevel = getFormattedTime(TTL)[2];
		final String secondsToLevel = getFormattedTime(TTL)[3];
		String sTTL = "0:00:00:00";
		if ((skills.getCurrentSkillExp(Constants.STAT_MINING) - mining[0]) > 0) {
			sTTL = daysToLevel + ":" + hoursToLevel + ":" + minutesToLevel
					+ ":" + secondsToLevel;
		}
		g.setColor(color1);
		g.fillRoundRect(548, 206, 188, 258, 16, 16);
		g.setColor(color2);
		g.setStroke(stroke1);
		g.drawRoundRect(548, 206, 188, 258, 16, 16);
		g.drawImage(img1, 414, 161, null);
		g.setFont(font1);
		g.setColor(color3);
		g.drawString("Henry's Essence Miner", 575, 230);
		g.setFont(font2);
		g.drawString("Run Time:" + hours + "h " + minutes + "min " + seconds
				+ "sec", 552, 253);
		g.drawString("Status: " + status, 552, 276);
		g.drawString(
				"Xp Gained: "
						+ insertCommas(""
								+ (skills
										.getCurrentSkillExp(Constants.STAT_MINING) - mining[0])),
				552, 299);
		g.drawString("Xp Per Hour: " + insertCommas("" + xpHour), 552, 322);
		g.drawString("Money Made: "
				+ insertCommas("" + (currentOrePrice * count)), 552, 345);
		g.drawString("Money Per hour: " + insertCommas("" + gpHour), 552, 368);
		g.drawString("Ess Mined:" + count, 552, 391);
		g.drawString("Ess Per Hour: " + insertCommas("" + oreHour), 552, 414);
		g.drawString("ETA: " + sTTL, 552, 437);
		g.drawString("Script: Henry & Paint: Levest28", 552, 460);
	}

	public String[] getFormattedTime(final long timeMillis) {
		long millis = timeMillis;
		final long days = millis / (24 * 1000 * 60 * 60);
		millis -= days * (24 * 1000 * 60 * 60);
		final long hours = millis / (1000 * 60 * 60);
		millis -= hours * 1000 * 60 * 60;
		final long minutes = millis / (1000 * 60);
		millis -= minutes * 1000 * 60;
		final long seconds = millis / 1000;
		final String dayString = String.valueOf(days);
		String hoursString = String.valueOf(hours);
		String minutesString = String.valueOf(minutes);
		String secondsString = String.valueOf(seconds);
		if (hours < 10) {
			hoursString = 0 + hoursString;
		}
		if (minutes < 10) {
			minutesString = 0 + minutesString;
		}
		if (seconds < 10) {
			secondsString = 0 + secondsString;
		}
		return new String[] { dayString, hoursString, minutesString,
				secondsString };
	}

	private String insertCommas(final String str) {
		return str.length() < 4 ? str : (insertCommas(str.substring(0,
				str.length() - 3))
				+ "," + str.substring(str.length() - 3, str.length()));
	}

	public RSObject getRocks() {
		return getNearestObjectByID(ess);
	}

	public boolean atDoor() {
		final RSTile a = doorTile;
		final RSObject obj = getTopObjectAt(a);
		if(obj != null){
			if(obj.isOnScreen())
                return obj.action("Open");
		}
		return false;
	}

	public boolean checkForDoor() {
		if (getTopObjectAt(doorTile) == null)
			return false;
		return getTopObjectAt(doorTile).getID() == doorID;
	}

	public boolean isMining() {
		if(justIn){
			failSafe = 0;
			return false;
		}
		if (getMyPlayer().isMoving()) {
			failSafe = 0;
			return true;
		}
		if (getMyPlayer().getAnimation() != -1) {
			failSafe = 0;
			return true;
		} else {
			if (failSafe >= 100) {
				failSafe = 0;
				return false;
			}
			failSafe++;
			return true;
		}
	}

	public int antiBan() {
		final int r = random(0, 6001);
		if (r >= 0 && r <= 10) {
			moveMouseRandomly(50);
			return 50;
		}
		if (r == 20) {
			moveMouseRandomly(300);
			return 50;
		}
		if (r == 30) {
			int an = getCameraAngle();
			an += random(-45, 46);
			if (an < 0) {
                an = 0;
            }
			if (an > 360) {
                an = 0;
            }
			setCameraRotation(an);
			return 50;
		}
		if (r == 40 && random(0, 100) == 5) {
			openTab(Constants.TAB_STATS);
			wait(random(200, 2000));
			ifaces.getInterface(320).getChild(37).getArea();
			final Rectangle pos = ifaces.getInterface(320).getChild(3)
					.getArea();
			final int midx = (int) (pos.getMinX() + pos.getWidth() / 2);
			final int midy = (int) (pos.getMinY() + pos.getHeight() / 2);

			moveMouse(midx + random(-7, 7), midy + random(-7, 7));
			wait(random(900, 3000));
			return 500;
		}
		return 10;
	}

	@Override
	public int loop() {
		if (!setAltitude) {
			status = "Startup camera";
			setCameraAltitude(true);
			wait(random(300, 400));
			setAltitude = true;
			return random(400, 600);
		}
		try {
			if (!isInventoryFull()) {
				if (bankArea.contains(getLocation())) {
					status = "Walking to Aubury";
					walking(1);
					return 100;
				}
				if (area.contains(getLocation())) {
					status = "Teleporting";
					final RSNPC a = getNearestNPCByID(teleport);
					if (a != null) {
						if (atNPC(a, "Teleport")) {
							failSafe = 100;
							int fail = 0;
							while (getLocation().getY() > 3200
									&& getLocation().getX() < 5000 && getRocks() == null) {
								fail++;
								if (fail >= 8)
									return 10;
								if (getMyPlayer().isMoving()) {
                                    fail = 0;
                                }
								if (getMyPlayer().getAnimation() != -1) {
                                    fail = 0;
                                }
								wait(500);
							}
							justIn = true;
							return 100;
						}
					}
					return 10;
				}
				if (getLocation().getY() > 3200 && getLocation().getX() < 5000) {
					if (distanceTo(doorTile) < 8) {
						if (checkForDoor()) {
							status = "Opening the Door";
							atDoor();
							int fail = 0;
							while (checkForDoor()) {
								fail++;
								wait(10);
								if (getMyPlayer().isMoving()) {
                                    fail = 0;
                                }
								if (fail >= 300)
									return 10;
							}
							return 100;
						} else {
							status = "Getting inside";
							atTile(area.getRandomTile(), "alk here");
							int fail = 0;
							while (!area.contains(getLocation())) {
								fail++;
								wait(10);
								if (getMyPlayer().isMoving()) {
                                    fail = 0;
                                }
								if (getMyPlayer().getAnimation() != -1) {
                                    fail = 0;
                                }
								if (fail >= 300)
									return 10;
							}
							return 100;
						}
					} else {
						walking(1);
						return 100;
					}
				} else {
					if (!isMining()) {
						status = "Gonna mine";
						final RSObject r = getRocks();
						if (r != null) {
							if (!r.isOnScreen() || distanceTo(r) > 4) {
								if (r.isOnMinimap()) {
									walkTileMiniM(r.getLocation());
								} else {
									walkPath(generateFixedPath(r.getLocation()));
									return 500;
								}
								int fail = 0;
								while (!r.isOnScreen()) {
									fail++;
									wait(10);
									if (getMyPlayer().isMoving()) {
                                        fail = 0;
                                    }
									if (getMyPlayer().getAnimation() != -1) {
                                        fail = 0;
                                    }
									if (fail >= 100)
										return 10;
								}
							}
							status = "Ess!";
							if (atEss(r, "Mine")) {
								int fail = 0;
								while (getMyPlayer().getAnimation() == -1) {
									fail++;
									if (getMyPlayer().isMoving()) {
                                        fail = 0;
                                    }
									wait(100);
									if (fail >= 20)
										return 10;
								}
								justIn = false;
								return 100;
							}
							return 10;
						}
					} else {
						status = "Mining";
						return antiBan();
					}
				}
			} else {
				if (getLocation().getY() > 3200 && getLocation().getX() < 5000) {
					if (bankArea.contains(getLocation())) {
						status = "Banking";
						while (getMyPlayer().isMoving()) {
                            wait(200);
                        }
						if (!bank.isOpen()) {
							handleBank();
							wait(random(600, 900));
							if (bank.isOpen()) {
								if (getInventoryCount(OreInvID) > 0) {
									if (inInventory(pickaxes)) {
										bank.depositAllExcept(pickaxes);
										return 100;
									} else {
										bank.depositAll();
										return 100;
									}
								}
							}
						}
						return 100;
					}
					if (area.contains(getLocation())) {
						if (checkForDoor()) {
							status = "Opening the Door";
							atDoor();
							int fail = 0;
							while (checkForDoor()) {
								fail++;
								wait(10);
								if (getMyPlayer().isMoving()) {
                                    fail = 0;
                                }
								if (fail >= 300)
									return 10;
							}
							return 100;
						} else {
							status = "Walking to Bank";
							walking(2);
							return 100;
						}
					} else {
						status = "Walking to bank";
						walking(2);
						return 100;
					}
				} else {
					status = "Going through portal";
					final RSObject p = getNearestObjectByID(portal);
					if (p != null) {
						if (!p.isOnScreen()) {
							walkTileMiniM(p.getLocation());
							int fail = 0;
							while (!p.isOnScreen()) {
								fail++;
								wait(10);
								if (getMyPlayer().isMoving()) {
                                    fail = 0;
                                }
								if (getMyPlayer().getAnimation() != -1) {
                                    fail = 0;
                                }
								if (fail >= 300)
									return 10;
							}
						}
						if (atObject(p, "Enter")) {
							wait(100);
							int fail = 0;
							while (getNearestObjectByID(portal) != null) {
								fail++;
								if (getMyPlayer().isMoving()) {
                                    fail = 0;
                                }
								if (getMyPlayer().getAnimation() != -1) {
                                    fail = 0;
                                }
								if (fail >= 400)
									return 300;
								wait(10);
							}
						}
					}
				}
			}
		} catch (final Exception ignored) {
		}
		return 10;
	}
	

	public boolean handleBank() {
		try {
			int ct = 0;
			if (!bank.isOpen()) {
				wait(random(500, 800));
				if (bank.open()) {
					while (ct++ < 30 && !bank.isOpen()) {
						wait(180);
					}
				}
			}
		} catch (final Exception e) {
		}
		return bank.isOpen();
	}

	public boolean atEss(final RSObject tree, final String cmd) {
		int failsS = 0;
		while (getMenuActions().size() != 0 && !getMenuActions().contains(cmd)
				&& failsS != 10) {
			final Point p = tree.getModel().getModelPoints()[random(0, tree
					.getModel().getModelPoints().length)];
			if (pointOnScreen(p)) {
				moveMouse(p, 5, 5);
			}
			failsS++;
		}
		if (getMenuActions().size() == 0)
			return false;
		if (failsS == 100)
			return false;
		if (getMenuActions().contains(cmd))
            return atMenu(cmd);
		return false;
	}

	public boolean walking(final int a) {
		if (a == 1) {
			setRunning();
			walkPath(PathName);
		}
		if (a == 2) {
			setRunning();
			walkPath(reversePath(PathName));
		}
		return true;
	}

	public void walkPath(final RSTile[] path) {
		if (path == null)
			return;
		setRunning();
		if (distanceTo(path[path.length - 1]) < 4)
			return;
		while (distanceTo(path[path.length - 1]) > 3) {
			final RSTile cur = getNearest(path);
			walkTileMiniM(cur);
			int fail = 0;
			while (!getMyPlayer().isMoving()) {
				fail++;
				if (fail >= 10)
					return;
				sleep(300);
			}
			while (getMyPlayer().isMoving() && distanceTo(cur) > 3) {
                sleep(100);
            }
			if (rest && (getEnergy() < 10 + random(1, 10) || getEnergy() < 15)) {
				rest(random(80, 100));
			}
		}
	}

	public RSTile getNearest(final RSTile[] path) {
		RSTile best = new RSTile(-1, -1);
		for (final RSTile c : path) {
			if (c == null) {
                continue;
            }
			if (calc.isTileOnMinimap(c)) {
				best = c;
			}
		}
		return best;
	}

	public boolean inInventory(final int... itemID) {
		try {
			for (final int i : itemID) {
				if (getInventoryCount(i) != 0)
                    return true;
			}
		} catch (final Exception e) {
		}
		return false;
	}

	public void setRunning() {
		if (isLoggedIn()) {
			if (getEnergy() > random(60,71) && !isRunning()) {
				wait(random(500, 900));
				setRun(true);
				wait(random(300, 500));
			}
		}
	}

}